import { useMemoizedFn } from 'ahooks';
import type { TreeDataNode, TreeProps } from 'antd';

const useTreeDrag = (options: {
  loop: Function;
  checkSameName: Function;
  draggable: any;
  fieldNames?: TreeProps['fieldNames'];
  treeData?: any[];
  dragChecker?: (info: any) => boolean;
  forceUpdate?: () => void;
}) => {
  const { loop, checkSameName, draggable, fieldNames, treeData, dragChecker, forceUpdate } = options;
  const { children = 'children' } = fieldNames || {};

  const onDrop: TreeProps['onDrop'] = useMemoizedFn((info) => {
    if (!draggable) return; // 如果不可拖动

    if (!treeData || !forceUpdate) return; // 如果没有相关数据和事件

    if (dragChecker && !dragChecker(info)) return; // 节点不是个有效的拖动

    const dropKey = info.node.key;
    const dragKey = info.dragNode.key;
    const dropPos = info.node.pos.split('-');

    // the drop position relative to the drop node, inside 0, top -1, bottom 1
    const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);

    const data = treeData;
    const callbacks: Function[] = [];

    // Find dragObject
    let dragObj: TreeDataNode;
    let ar: TreeDataNode[] = [];

    loop(data, dragKey, (item, index, arr) => {
      dragObj = item;
      callbacks.push(() => arr.splice(index, 1));
    });

    // 拖动到顶层目录
    if (!info.dropToGap) {
      loop(data, dropKey, (item) => {
        item[children] = item[children] || [];
        ar = item[children];
      });

      callbacks.push(() => ar.unshift(dragObj));
    }
    // 拖动到一个同岑目录下的
    else {
      let i: number;
      loop(data, dropKey, (_item, index, arr) => {
        ar = arr;
        i = index;
      });

      callbacks.push(() => {
        if (dropPosition === -1) {
          // Drop on the top of the drop node
          ar.splice(i!, 0, dragObj!);
        } else {
          // Drop on the bottom of the drop node
          ar.splice(i! + 1, 0, dragObj!);
        }
      });
    }

    // 同名检验
    checkSameName(dragObj!, ar)
      .then(() => {
        callbacks.forEach((c) => c());
        forceUpdate();
      })
      .finally(() => {
        callbacks.length = 0;
      });
  });

  return { onDrop };
};

export default useTreeDrag;
